#include "sound.h"

#ifndef SKYID_DISABLE_SOUND
namespace SkyID 
{

#pragma pack(push,2)
struct WAVHeader
{
	// RIFF header
	uint32 chunkID;			// == 0x46464952 ("RIFF")
	uint32 chunkSize;		// == 8 + (8 + soundChunkSize) + (8 + dataChunkSize)
	uint32 format;			// == 0x45564157 ("WAVE")
	// Sound data format
	uint32 soundChunkID;	// == 0x20746D66 ("fmt ")
	uint32 soundChunkSize;	// 16, PCM
	uint16 audioFormat;		// 1, without compression
	uint16 numChannels;		// 1=Mono, 2=Stereo, etc
	uint32 sampleRate;		// 8000, 22100, 44100, etc
	uint32 byteRate;		// == sampleRate * numChannels * bitsPerSample/8
	uint16 blockAlignment;	// == numChannels * bitsPerSample/8
	uint16 bitsPerSample;	// 8, 16, etc
	// Data subchunk
	uint32 dataChunkID;		// == 0x61746164 ("data")
	uint32 dataChunkSize;	// == numSamples * numChannels * bitsPerSample/8
	// And below is actual data, dataSize = dataChunkSize
};
#pragma pack(pop)

SoundWAV::SoundWAV(Reader *reader)
{
	if (!isValid())
		return;
	mBuffer = new ALuint;
	alGenBuffers(1, mBuffer);
	setValid(check() && open(reader));
}

SoundWAV::~SoundWAV()
{
	stop();
	alSourcei(mID, AL_BUFFER, 0);
	alDeleteBuffers(1, mBuffer);
	check();
	delete mBuffer;
	mBuffer = NULL;
}

bool SoundWAV::open(Reader *reader)
{
	LOG_ASSERT(reader && reader->isValid());

	WAVHeader hdr;

	reader->read((char*)&hdr, sizeof(hdr));
	if (hdr.chunkID!=0x46464952 || hdr.format!=0x45564157
		|| hdr.soundChunkID!=0x20746D66 || hdr.dataChunkID!=0x61746164)
	{
		LOG_MSG("SoundWAV: wrong file signature\n");
		return false;
	}

	if ((hdr.numChannels != 1 && hdr.numChannels != 2)
		|| (hdr.bitsPerSample != 8 && hdr.bitsPerSample != 16))
	{
		LOG_MSG("SoundWAV: incorrect WAV format\n");
		return false;
	}

	mFormat = (hdr.numChannels==1
		? (hdr.bitsPerSample==8 ? AL_FORMAT_MONO8 : AL_FORMAT_MONO16)
		: (hdr.bitsPerSample==8 ? AL_FORMAT_STEREO8 : AL_FORMAT_STEREO16) );

	mFrequency = hdr.sampleRate;

	char *data = new char[hdr.dataChunkSize];
	reader->read(data, hdr.dataChunkSize);

	alBufferData(*mBuffer, mFormat, data, hdr.dataChunkSize, mFrequency);
	alSourcei(mID, AL_BUFFER, *mBuffer);

	delete [] data;
	return check();
}

} // namespace SkyID
#endif // SKYID_DISABLE_SOUND
